/*
 * imagematrix.h
 *
 *  Created on: Feb 27, 2011
 *      Author: Mo
 */
#pragma once
#include "cmconstants.h"
#include "cluster.h"
#include "neighborhood.h"
#include "longinstance.h"
#include <iostream>

using namespace std;

//class Neighborhood;

/**
 * This class holds a binary image in a matrix, in which each element is either white(0) or black(1).
 */
class ImageMatrix
{
private:
	int rowNum; 						//!< Number of image rows
	int colNum;							//!< Number of image columns
	//int clusterNum;					//!< Number of continues clusters of "1"s in the image. Now depreciated because of clusters.size()
	float clusterability;				//!< A measure telling how easy it is to cluster the image
	int data[MROWS][MCOLS];				//!< The 2D array holding the value of the pixels in the image.
	int globalCluster[MROWS][MCOLS];	//!< The element(i,j) in this matrix tells to which cluster the pixel(i,j) in the image belongs.
	std::vector<Cluster> clusters;		//!< A vector of all clusters of 1 in the object.


public:

	ImageMatrix();
	ImageMatrix(int rowNum, int colNum);				//!< Sets all the elements to -1;
	ImageMatrix(const ImageMatrix& other);				//!< Copy Constructor
	ImageMatrix(const string& fileName, int r, int c);	//!< Reads the data from a file with given size.
	ImageMatrix(const string& fileName);				//!< Reads the data from a file
	ImageMatrix(int** sourceData, int r, int c);		//!< Copies data from a given 2D array
	ImageMatrix(int sourceData[][MCOLS], int r, int c);	//!< Copies data from a given 2D array
	~ImageMatrix();

	int getValue(int row, int col) const;				//!< Returns the element in the given row and column.
	/** This returns the value of the 'nbAddress'th neighbour, considering that the rotational addressing is
	 *  used for neighbors. That is starting from the upper left corner and going clockwise in a halazooni!
	 */
	int getValueWithRotationalIndex(int row, int col, int nbAddress) const;
	int getClusterNum (void) const;						//!< Returns the number of clusters in the image.
	int getRowNum(void) const;							//!< Returns the number of rows in the image/matrix.
	int getColNum(void) const;							//!< Returns the number of columns in the image/matrix.
	//Neighborhood getNeighborhood(int row, int col) const; //!< Returns the neighborhood arround the given pixel.

	void setRowNum(int r);								//!< Sets the number of rows in the image/matrix
	void setColNum(int c);								//!< Sets the number of columns in the image/matrix
	void setRowColNum (int r, int c);					//!< Sets the number of rows in the image/matrix
	void setData_noClusterUpdate (int r, int c, int v);	//!< Sets the value of specified pixel to v

	void saveToBMP(const string& fileName) const;		//!< Saves the data of this object to an existing BMP image on disk.
	void saveToTXT(string fileName) const;				//!< Saves the data of this object to a text file on disk. The file does not need to pre-exist.
		
	/** Copies the neighborhood centered in row and col to the given Neighborhood object.
	*/
	//void getNeighborhood (int row, int col, Neighborhood& neighborhood) const;


	/**
	 * Sets the clusterNum, the number of clusters in the binary image.
	 * Note that this function does not calculate the number of clusters,
	 * but simply receives that as input.
	 * \param n The number of clusters.
	 */
	void setClusterNum (int n);

	/**
	 * Loads the whole data matrix which corresponds to the image.
	 * \param sourceData Pointer to a 2D array consisting of the source datato be loaded
	 * to the object's data.
	 * \param r number of rows in the sourceData
	 * \param c number of columns in the sourceData
	 */
	void load(int** sourceData, int r, int c);

	/**
	 * Loads the whole data matrix which corresponds to the image.
	 * \param sourceData A 2D array consisting of the source datato be loaded
	 * to the object's data.
	 * \param r number of rows in the sourceData
	 * \param c number of columns in the sourceData
	 */
	void load(int sourceData[][MCOLS], int r, int c);

	/**
	 *  Loads the whole data matrix with the given 2-D array .
	 *  \param dourceData The 2D array to be loaded to the data matrix.
	 */
	void load(int sourceData[][MCOLS]);

	/**
	 *  Loads the whole data matrix with the given 2-D array.
	 *  \param dourceData The pointer to the 2D array to be loaded to the data matrix.
	 */
	void load(int** sourceData);

	/**
	 * Resets all the elements in data matrix to zero.
	 */
	void clean (void);

//	/**
//	 * Calculates the number of clusters in the image. Sets the clusterNum and returns that number.
//	 */
//	int findClustersNum(void);

	/**
	 * Calculates the value for clusterability, sets the object's clusterability and returns it.
	 */
	float findClusterability(void);

	/**
	 * Updated the clusters vector by recalculating all of the clusters.
	 * also updates the globalCluster 2D array.
	 */
	void refreshClusters (void);

	/**
	 * Returns the specified Cluster
	 * \param index The index of the Cluster object in the clusters vector to be returned.
	 * \return The specified cluster.
	 */
	Cluster returnCluster (int index);

	/**
	 * Adds the given pixel to the globalCluster 2D array, and sets its cluster number to the given value
	 * \param p The pixel to be added.
	 * \param clusterIndex The cluster number of the pixel that is about to be added.
	 */
	void addPixelToGlobalCluster (Pixel p, int clusterIndex);

	/**
	 * Prints the 2D array this->data to the screen.
	 */
	void printData(void) const;

	/**
	 * Prints the 2D array this->globalCluster to the screen.
	 */
	void printGlobalCluster(void) const;

	ImageMatrix& operator= (const ImageMatrix& other);

	//Returns the number of pixels with the same value in both caller and other.
	int countSimilarity (const ImageMatrix& other) const;

	//Returns the number of pixels with different values in the caller and other object.
	int countDifferences (const ImageMatrix& other) const;

	friend ostream& operator<< (ostream& stream, const ImageMatrix& im);

};


 //#endif /* IMAGEMATRIX_H_ */